import 'dart:convert';

import 'package:flutter/material.dart';
import 'package:flutter_secure_storage/flutter_secure_storage.dart';
import 'package:hive_ce/hive.dart';
import 'package:synchronized/synchronized.dart';

/// 通用加密存储基类
class BaseSecureStorage {
  final String _boxName;
  final String _encryptionKeyName;
  final FlutterSecureStorage _secureStorage = const FlutterSecureStorage();
  final Lock _initLock = Lock();

  late final Box _box;
  bool _initialized = false;

  BaseSecureStorage({
    required String boxName,
    required String encryptionKeyName,
  }) : _boxName = boxName,
       _encryptionKeyName = encryptionKeyName;

  Future<void> _ensureInitialized() async {
    if (!_initialized) {
      await _initLock.synchronized(() async {
        if (!_initialized) await _initialize();
      });
    }
  }

  Future<void> _initialize() async {
    final key = await _getEncryptionKey();
    _box = await Hive.openBox(_boxName, encryptionCipher: HiveAesCipher(key));
    _initialized = true;
  }

  Future<List<int>> _getEncryptionKey() async {
    final existingKey = await _secureStorage.read(key: _encryptionKeyName);
    if (existingKey != null) return base64Url.decode(existingKey);

    final newKey = Hive.generateSecureKey();
    await _secureStorage.write(
      key: _encryptionKeyName,
      value: base64UrlEncode(newKey),
    );
    return newKey;
  }

  // 公共方法
  Future<BaseSecureStorage> init() async {
    await _ensureInitialized();
    return this;
  }

  Future<void> close() async {
    if (_initialized) {
      await _box.close();
      _initialized = false;
    }
  }

  @protected
  Future<void> saveData(String key, dynamic value) async {
    await _ensureInitialized();
    await _box.put(key, value);
  }

  @protected
  dynamic getData(String key, {dynamic defaultValue}) {
    return _initialized
        ? _box.get(key, defaultValue: defaultValue)
        : defaultValue;
  }

  @protected
  Future<void> clearData() async {
    if (_initialized) await _box.clear();
  }

  @protected
  Future<void> delete(String key) async {
    await _box.delete(key);
  }
}
